package jframe;
 
import java.awt.Dimension;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
 
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
 
@SuppressWarnings("serial")
public class Server extends JFrame {
 
    private JScrollPane pane;
    private JTextArea textAreaShow;
    private ServerSocket serverSocket;
    private List<Socket> connectedSockets = new ArrayList<Socket>();
 
    public Server() {
        initFrame();
        int port = 8888;
        try {
            startServer(port);
        } catch (IOException e) {
            String text = "以端口号" + port + "启动Socket服务失败,检查端口是否被占用，并重新启动服务";
            textAreaShow.append(text);
        }
    }
 
    // 窗口初始化
    private void initFrame() {
 
        setTitle("服务端");
        setSize(500, 400);
        setMinimumSize(new Dimension(250, 200));
 
        setDefaultCloseOperation(DO_NOTHING_ON_CLOSE);
        addWindowListener(new WindowAdapter() {
            @Override
            public void windowClosing(WindowEvent event) {
                if (serverSocket != null) {
                    try {
                        serverSocket.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                        System.exit(1);
                    }
                    System.exit(0);
                }
            }
        });
 
        // 重写JTextArea的append方法
        textAreaShow = new JTextArea() {
            @Override
            public void append(String str) {
                str = (new Date().toString()) + "  " + str + "\n";
                super.append(str);
            }
        };
        textAreaShow.setEditable(false);
        textAreaShow.setLineWrap(true);
        textAreaShow.setWrapStyleWord(true);
 
        pane = new JScrollPane(textAreaShow,
                JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED,
                JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
 
        add(pane);
 
        setVisible(true);
    }
 
    // 启动服务，等待客户端连接
    private void startServer(int port) throws IOException {
        ExecutorService executorService = Executors.newCachedThreadPool();
        serverSocket = new ServerSocket(port);
        Socket socket;
        textAreaShow.append("服务已启动，端口号" + port);
        while (true) {
            socket = serverSocket.accept();
            String connectedMsg = "端口号" + socket.getPort() + " 已上线";
            textAreaShow.append(connectedMsg);
            dispatchMessage(connectedMsg);
            connectedSockets.add(socket);
            executorService.execute(new ServerThread(socket));
        }
    }
 
    // 向各客个连接转发发送消息
    private void dispatchMessage(String str) {
        DataOutputStream dos;
        for (Socket soc : connectedSockets) {
            try {
                dos = new DataOutputStream(soc.getOutputStream());
                dos.writeUTF(str);
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
 
    // 处理各连接的线程
    private class ServerThread implements Runnable {
 
        private Socket socket;
        private DataInputStream in;
 
        public ServerThread(Socket socket) {
            this.socket = socket;
            try {
                in = new DataInputStream(socket.getInputStream());
            } catch (IOException e) {
                textAreaShow.append(e.getMessage());
            }
        }
 
        @Override
        public void run() {
            try {
                String str;
                while ((str = in.readUTF()) != null) {
                    str = socket.getPort() + "说：" + str;
                    textAreaShow.append(str);
                    dispatchMessage(str);
                }
            } catch (IOException e) {
                textAreaShow.append("Port " + socket.getPort() + " 已下线");
                connectedSockets.remove(socket);
                closeSocket();
            }
        }
 
        private void closeSocket() {
            if (in != null) {
                try {
                    in.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (socket != null) {
                try {
                    socket.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
 
    public static void main(String[] args) {
        new Server();
    }
}